﻿using Blazor.Diagrams.Core;
using Blazor.Diagrams.Core.Geometry;
using Blazor.Diagrams.Core.Models;
using Blazor.Diagrams.Core.Models.Base;
using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Newtonsoft.Json;
using System.Diagnostics.CodeAnalysis;

namespace OnWork.DataCenter.Shared.Pages.DataStandard.Designer
{
    public partial class StandardDesigner : ComponentBase
    {
        /// <summary>
        /// 图表对象
        /// </summary>
        private Diagram diagram { get; set; } = new Diagram();

        /// <summary>
        /// 随机数
        /// </summary>
        private static readonly Random _random = new Random();

        [Inject]
        [NotNull]
        private DialogService? DialogService { get; set; }

        [Inject]
        [NotNull]
        private ToastService? ToastService { get; set; }

        /// <summary>
        /// OnInitialized 方法
        /// </summary>
        protected override void OnInitialized()
        {
            base.OnInitialized();

            var options = new DiagramOptions
            {
                DeleteKey = "Delete", // What key deletes the selected nodes/links
                DefaultNodeComponent = null, // Default component for nodes
                AllowMultiSelection = true, // Whether to allow multi selection using CTRL
                Links = new DiagramLinkOptions
                {
                    EnableSnapping = true,
                    DefaultRouter = new Blazor.Diagrams.Core.Router(Routers.Orthogonal),
                    DefaultPathGenerator = new PathGenerator(PathGenerators.Straight),
                    //设置默认线的头的形状
                    Factory = (Diagram diagram, PortModel sourcePort) => { return new LinkModel(sourcePort) { TargetMarker = LinkMarker.Arrow }; },
                    // Options related to links
                },
                Zoom = new DiagramZoomOptions
                {
                    Enabled = false, //
                    Minimum = 0.5, // Minimum zoom value
                    Inverse = false, // Whether to inverse the direction of the zoom when using the wheel
                                     // Other
                }
            };

            diagram = new Diagram(options);
            diagram.RegisterModelComponent<StandardNode, StandardWidget>();
            RegisterEvents();
            //diagram = new Diagram();
            //InitTest();
            //var node1 = NewNode(50, 50);
            //var node2 = NewNode(300, 300);
            //var node3 = NewNode(300, 50);
            //diagram.Nodes.Add(new[] { node1, node2, node3 });

            //diagram.Links.Add(new LinkModel(node1.GetPort(PortAlignment.Right), node2.GetPort(PortAlignment.Left))
            //    {
            //        SourceMarker = LinkMarker.Arrow,
            //        TargetMarker = LinkMarker.Arrow
            //    });
            //diagram.Links.Add(new LinkModel(node2.GetPort(PortAlignment.Right), node3.GetPort(PortAlignment.Right))
            //    {
            //        Router = Routers.Orthogonal,
            //        PathGenerator = PathGenerators.Straight,
            //        SourceMarker = LinkMarker.Arrow,
            //        TargetMarker = LinkMarker.Arrow
            //    });
        }

        /// <summary>
        /// 当前的连线
        /// </summary>
        private BaseLinkModel currentLink;

        /// <summary>
        /// 时间注册
        /// </summary>
        private void RegisterEvents()
        {
            //连接添加
            diagram.Links.Added += (l) =>
            {
                if (l.SourceNode != null)
                {
                    currentLink = l; //修改当前的连线
                }
            };

            //鼠标抬起
            diagram.MouseUp += (m, e) =>
            {
                //判断是否是节点
                if (currentLink != null)
                {
                    var sd = currentLink.SourceNode as StandardNode; //原始节点
                    var td = currentLink.TargetNode as StandardNode; //目标节点

                    if (sd != null && td != null)
                    {
                        if (sd.OutType != td.DataType)
                        {
                            ToastService?.Error("连线错误", $"当前节点出节点{sd.OutType}与目标节点{td.DataType}不符,不能连线!");
                            diagram.Links.Remove(currentLink);
                        }
                    }
                    currentLink = null;
                }

                //ToastService?.Information("测试",$"MouseUp, Type={m?.GetType().Name}, ModelId={m?.Id}");
                //StateHasChanged();
            };
        }

        private void InitTest()
        {
            diagram.RegisterModelComponent<StandardNode, StandardWidget>();

            //var node = new NodeModel(new Point(20, 20));
            //node.AddPort(PortAlignment.Top);
            //node.AddPort(PortAlignment.Right);
            //node.AddPort(PortAlignment.Bottom);
            //node.AddPort(PortAlignment.Left);

            diagram.Nodes.Add(new[] { NewStandardNode(20, 20), NewStandardNode(100, 100), NewStandardNode(300, 300) });
        }

        private StandardNode NewStandardNode(double x, double y)
        {
            var node = new StandardNode(new Point(x, y));
            node.Name = "text";
            node.ID = 123123;
            node.AddPort(PortAlignment.Bottom);
            node.AddPort(PortAlignment.Top);
            node.AddPort(PortAlignment.Left);
            node.AddPort(PortAlignment.Right);
            return node;
        }

        /// <summary>
        /// 添加节点
        /// </summary>
        private async void AddNode()
        {
            var result = await DialogService.ShowModal<StandardListDialog>(new ResultDialogOption()
            {
                Title = "选择需要添加的对象",
                ComponentParamters = new Dictionary<string, object>
                {
                    //[nameof(ResultDialogDemo.Value)] = DemoValue1,
                    [nameof(StandardListDialog.ValueChanged)] = EventCallback.Factory.Create<List<DataStandardConfigVO>>(this, v =>
                    {
                        foreach (var item in v)
                        {
                            var x = _random.Next(0, 1000);// _random.Next(0, (int)diagram.Container.Width - 120);
                            var y = 80;//_random.Next(0, (int)diagram.Container.Height - 100);
                            var node = new StandardNode(new Point(x, y));
                            node.AddPort(PortAlignment.Left);
                            node.AddPort(PortAlignment.Right);
                            item.Adapt(node);
                            diagram.Nodes.Add(node); //添加节点
                        }
                    })
                }
            }); ;
        }

        /// <summary>
        /// 添加节点
        /// </summary>
        private async void CopySelectNode()
        {
            var selectModels = diagram.Nodes.Where(x => x.Selected == true).ToList(); //获取选中的模型;
            if (selectModels.Any()==false)
            {
                //无选中则退出
                await ToastService?.Error("发生错误", "请选择需要复制的对象!");
                return;
            }

            foreach (var item in selectModels)
            {
                var x = _random.Next(0, 1000);// _random.Next(0, (int)diagram.Container.Width - 120);
                var y = 80;//_random.Next(0, (int)diagram.Container.Height - 100);
                var myModel = item as StandardNode;
                if (myModel!=null)
                {
                    var node = new StandardNode(new Point(x, y))
                    {
                        ID = myModel.ID,
                        DataDemo = myModel.DataDemo,
                        Name = myModel.Name,
                        DataType = myModel.DataType,
                        OutType = myModel.OutType,
                        StandardConfig = myModel.StandardConfig
                    };
                        
                    node.AddPort(PortAlignment.Left);
                    node.AddPort(PortAlignment.Right);

                    //item.Adapt(node);
                    diagram.Nodes.Add(node); //添加节点
                }
            }
        }

        private static string tmpJson;

        /// <summary>
        /// 保存为JSOn
        /// </summary>
        /// <returns>图形json,配置文件Json字符串</returns>
        public (string, string) SaveJsonData()
        {
            //var json = JsonConvert.SerializeObject(new
            //{
            //    Nodes = diagram.Nodes.Cast<object>(),
            //    Links = diagram.Links.Cast<object>()
            //}, Formatting.Indented, new JsonSerializerSettings
            //{
            //    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            //});

            StandardDesignerSaveDto dto = new StandardDesignerSaveDto();
            dto.Links = diagram!.Links.Select(m => m).ToList().Adapt<List<LinkDto>>();
            var nodes = diagram!.Nodes.Select(m => (StandardNode)m).ToList();
            //dto.Nodes = nodes.Adapt<List<NodeDto>>();

            List<NodeDto> nodeDtos = new List<NodeDto>();
            dto.Nodes = nodeDtos;
            if (nodes != null)
            {
                foreach (var node in nodes)
                {
                    NodeDto nDto = new NodeDto()
                    {
                        ID = node.ID,
                        DataType = node.DataType,
                        OutType = node.OutType,
                        Name = node.Name,
                        StandardConfig = node.StandardConfig,
                        DataDemo = node.DataDemo,
                        Id = node.Id,
                        Position = node.Position,
                        Size = node.Size,
                        Title = node.Title,
                    };
                    nDto.Ports = new List<PortDto>();

                    if (node.Ports != null)
                    {
                        foreach (var item in node.Ports)
                        {
                            PortDto nPort = new PortDto()
                            {
                                Id = item.Id,
                                ParentId = item.Parent.Id,
                                Position = item.Position,
                                Size = item.Size,
                                Alignment = item.Alignment,
                                Links = item.Links.Adapt<List<LinkDto>>(),
                            };
                            nDto.Ports.Add(nPort);
                        }
                    }
                    nodeDtos.Add(nDto);
                }
            }

            //dto.Nodes.ForEach(n =>
            //{
            //    n.DefinitionId = dto.Definition.Id;
            //    n.Ports.ForEach(p =>
            //    {
            //        p.DefinitionId = dto.Definition.Id;
            //        p?.Links?.ForEach(l =>
            //        {
            //            l.DefinitionId = dto.Definition.Id;
            //            l.Labels.ForEach(t => t.DefinitionId = dto.Definition.Id);
            //            l.Vertices.ForEach(t => t.DefinitionId = dto.Definition.Id);
            //        });

            //    });
            //});
            //dto.Links.ForEach(l =>
            //{
            //    l.DefinitionId = input.Definition.Id;
            //    l.Labels.ForEach(t => t.DefinitionId = input.Definition.Id);
            //    l.Vertices.ForEach(t => t.DefinitionId = input.Definition.Id);
            //});

            var json = JsonConvert.SerializeObject(dto);

            var configJson = JsonConvert.SerializeObject(dto.ToTreeVO());
            //var vo =  dto.ToTreeVO();
            //ToastService?.Success("显示JSOn", JsonConvert.SerializeObject(vo));
            return (json, configJson);
            //ToastService?.Success("显示JSOn", "暂存成功!");
            //await JSRuntime.InvokeVoidAsync("console.log", json);
        }

        /// <summary>
        /// 从JSOn开始加载
        /// </summary>
        /// <param name="json"></param>
        public void LoadFormjson(string json)
        {
            StandardDesignerSaveDto dto = JsonConvert.DeserializeObject<StandardDesignerSaveDto>(json);
            //首先情况节点
            diagram.Nodes.Clear();
            dto.Nodes.ForEach(sn =>
            {
                //var tn = (StandardNode)(sn);
                var tn = new StandardNode(sn.Id, sn.Position)
                {
                    Title = sn.Title ?? "",
                };
                sn.Adapt(tn);
                //if (sn?.ExtraProperties is not null)
                //    sn!.ExtraProperties.ExtraPropertyDataToObject<FlowNode>(tn);
                //添加节点
                sn?.Ports.ForEach(p =>
                {
                    PortModel portModel = new PortModel(p.Id, tn, p.Alignment, p.Position, p.Size)
                    {
                        Initialized = true
                    };
                    tn.AddPort(portModel);
                });
                diagram.Nodes.Add(tn);
            });
            var nodes = diagram.Nodes;

            //绘制连线
            dto.Links.ForEach(l =>
            {
                var sNode = nodes.First(m => m.Id == l.SourceNodeId.ToString());
                var sPort = sNode!.Ports.First(m => m.Id == l.SourcePortId.ToString());

                var tNode = nodes.First(m => m.Id.ToLower() == l.TargetNodeId?.ToString().ToLower());
                var tPort = tNode!.Ports.First(m => m.Id.ToString().ToLower() == l.TargetPortId?.ToString().ToLower());

                var ll = new LinkModel(l.Id.ToString(), sPort, tPort) { TargetMarker = l.TargetMarker, SourceMarker = l.SourceMarker };
                //ll.Content = string.Join(",", l.Labels);
                //ll.Paths = l!.Paths!.Split(",");
                //l.ExtraProperties.ExtraPropertyDataToObject<FlowLink>(ll);
                l.Labels.ForEach(b =>
                {
                    Point? offsetPoint = null;
                    if (b.OffsetX.HasValue)
                    {
                        offsetPoint = new Point(b.OffsetX.Value, b!.OffsetY!.Value);
                    }
                    ll.Labels.Add(new LinkLabelModel(ll, b.Id.ToString(), b?.Content ?? "", null, offsetPoint));
                });
                l.Vertices.ForEach(v =>
                {
                    // var jj = new LinkVertexModel(ll);
                    // jj.SetPosition( v.X!.Value, v.Y!.Value);
                    //jj.Id = "111";
                    // ll.Vertices.Add(jj );
                });

                diagram!.Links.Add(ll);
            });
        }
    }
}